//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	File		 :	Parse.h
//	Contents	 :	Header file for class CParse
//	Creation Date:	22/12/1999
//	Last Modified:	23/12/1999	lg
//	tabs width	 :	every 4 characters
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#if !defined(PARSE_H)
#define PARSE_H



#include "sequence.h"
#include <ctype.h>

//_______________________________________________________________________________________
//
//	Handle call backs from the parsing engine when there are errors or warnings
//	CConsole_ParseMessageCallback just dumps the stuff to the standard streams
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
struct CParseMessageCallback
{
	// return false to terminate parsing on warnings
	virtual bool Warning(const std::string& description, unsigned line) = 0;
	virtual void Error(const std::string& description, unsigned line) = 0;
	virtual void LengthsUnEqError(const std::string& s, const CSequence& seq) = 0;
};

struct CConsole_ParseMessageCallback: public CParseMessageCallback
{
	virtual bool Warning(const std::string& description, unsigned line);
	virtual void Error(const std::string& description, unsigned line);
	virtual void LengthsUnEqError(const std::string& s, const CSequence& seq);
};

class CParse
{
public:
	CParse(CParseMessageCallback& callback, unsigned msg1, unsigned msg2)
		:	MessageCallback(callback), m_InvalidFileMsg(msg1), m_ErrFileMsg(msg2),
			LineNumber(0), Data_Stream(0){}
	virtual bool	DoParse(char* const data_Stream, CSequence& outputSequence) = 0;
	unsigned	GetLineNum() const { return LineNumber;	};
	char*	GetDataStream() const { return Data_Stream;}
	//utility functions
	static void	SkipSpaces(char*& p) {while (*p && isspace(*p))++p;}
	static void	SkipToSpace(char*& p) {while (*p && !isspace(*p))++p;}
protected:
	//utility functions
	static void	PrepareNextLine(char*& nextLine, char*& Data, unsigned& lineNumber);
	static bool CheckMatchChars(const char*, char, unsigned count);

	bool	ParseErr(bool test, unsigned msgID, int num, const char* token = "");
	bool	ParseWarn(bool test, unsigned msgID, int num, const char* token = "");
	void	ParseErrLength(const CSequence& seq);
	void	DoErrMsg(unsigned msgID, int num, const char* token = "");
	bool	DoWarnMsg(unsigned msgID, int num, const char* token = "");
	void	SetErrMsges(unsigned warn, unsigned err){m_InvalidFileMsg = warn; m_ErrFileMsg = err;}
	int		MatchNames(const CSequence::vec_str&, const std::string& testName, int& first_Match);
private:
// private data
	CParseMessageCallback&	MessageCallback;

	//("This is not a valid xxx file.\r\n");
	unsigned m_InvalidFileMsg;
	//"There is an error in the xxx file.\r\n"
	unsigned m_ErrFileMsg;
protected:
// protected data is almost invariably a bad idea
	unsigned						LineNumber;	// 1-based line numbers
	char*						Data_Stream;// points to next character to be scanned

};


//_______________________________________________________________________________________
//
//	ParseErr
//
//		Internal function
//		if the error condition (test) is true:
//			Displays error message in a message box
//			Returns false (halting condition)
//		msgID is the resource id of the error message
//		num is the line number if positive
//		Last modified: lg 23/12/1999
//
//_______________________________________________________________________________________
inline bool CParse::ParseErr(bool test, unsigned msgID, int num, const char* token)
{
	if (test)
	{
		DoErrMsg(msgID, num, token);
		return true;
	}
	return false;
};



//_______________________________________________________________________________________
//
//	ParseWarn
//
//		Internal function
//		Displays warning message in a message box if the error condition (test) is true.
//		Only return false (halting condition) if user chooses not to proceed.
//		msgID is the resource id of the error message
//		num is the line number if positive
//		Last modified: lg 23/12/1999
//		NB inline because only used in this translational unit
//
//_______________________________________________________________________________________
inline bool CParse::ParseWarn(bool test, unsigned msgID, int num, const char* token)
{
	if (test)
		return DoWarnMsg(msgID, num, token);
	return false;
};

//_______________________________________________________________________________________
//
//	PrepareNextLine
//
//		Get Next line in the data stream and insert a null after it
//_______________________________________________________________________________________
inline void CParse::PrepareNextLine(char*& nextLine, char*& Data, unsigned& lineNumber)
{
	assert(nextLine);
	// get next line
	if (Data)
		Data = nextLine + 1;
	else
		Data = nextLine;
	nextLine = strchr(Data, '\n');
	if (nextLine)
		*nextLine = '\0';	// add null to only search within the line
	++lineNumber;			// 1-based line numbers
}
//_______________________________________________________________________________________
//
//	CheckMatchChars
//
//		will trap for 0 if c is not a null terminator
//_______________________________________________________________________________________
inline bool CParse::CheckMatchChars(const char* data, char c, unsigned count)
{
	assert(data);
	assert(c);
	unsigned i;
	for (i = 0; i < count; ++i)
		if (data[i] != c)
			return false;
	return true;
}

#endif // !defined(PARSE_H)
